"use strict"

/**
 * 数据库存储接口
 * sunny
 *  
 */
import { MongoClient, MongosOptions, MongoCallback, MongoError, Db, ObjectId } from 'mongodb';
import { resolve } from 'path';

let deasync = require('deasync');
/**
 * mongo 数据库定义
 */
let connect_prop = {
    uri: 'localhost', // ip
    port: 27017, // 端口
    db: 'jxlocaltax' // 数据库
};

export class Driver {
    dburi: string;
    custOptions: any;
    constructor(custOptions?: any) {
        if (custOptions) {
            this.custOptions = custOptions;
        } else {
            this.custOptions = connect_prop;
        }
        this.dburi = `mongodb://${this.custOptions.uri}:${this.custOptions.port}`;
    }

    find(collection: string, query: Object): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).find(query).toArray((err: MongoError, result: any[]): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }
    //collection集合名
    findSync(collection: string, query: Object): any {
        let result: any;
        this.find(collection, query).then((rs: any) => {
            result = rs;
        }, (err) => {
            console.error(err);
            result = [];
        });
        while (!result) {
            deasync.runLoopOnce();//放空循环，不占用CPU资源，指导取到数据为止
        }
        return result;
    }

    pagnate(collection: string, query: Object, offset: number, limit: number): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).find(query).skip(offset).limit(limit).toArray((err: MongoError, result: any[]): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    pagnateSync(collection: string, query: Object, offset: number, limit: number): any {
        let result: any;
        this.pagnate(collection, query, offset, limit).then((rs: any) => {
            result = rs;
        }, (err) => {
            result = [];
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    findOne(collection: string, query: Object): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).findOne(query, (err: MongoError, result: any): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    findOneSync(collection: string, query: Object): any {
        let result: any;
        this.findOne(collection, query).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    insert(collection: string, items: any[]): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).insertMany(items, (err: MongoError, result: any): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    insertSync(collection: string, items: any[]): any {
        let result: any;
        this.insert(collection, items).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    update(collection: string, query: Object, item: any): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).updateMany(query, { $set: item }, (err: MongoError, result: any): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    updateSync(collection: string, query: Object, item: any): any {
        let result: any;
        this.update(collection, query, item).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    delete(collection: string, query: any): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).deleteMany(query, (err: MongoError, result: any): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    deleteSync(collection: string, query: Object): any {
        let result: any;
        this.delete(collection, query).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    distinct(collection: string, query: Object, field: string): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                db.collection(collection).distinct(field, query, (err: MongoError, result: any): void => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(result);
                    }
                    client.close();
                });
            });
        });
        return q;
    }

    distinctSync(collection: string, query: Object, field: string): any {
        let result: any;
        this.distinct(collection, query, field).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    count(collection: string, query: Object): Promise<{}> {
        let q = new Promise((resolve, reject): void => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                let cnt = db.collection(collection).find(query).count();
                if (error) {
                    reject(error);
                } else {
                    resolve(cnt);
                }
                client.close();
            });
        });
        return q;
    }

    countSync(collection: string, query: Object): any {
        let result: any;
        this.count(collection, query).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }

    remove(collection: string, query: Object): Promise<{}> {
        let q = new Promise((resolve, reject) => {
            MongoClient.connect(this.dburi, (error: MongoError, client: Db): void => {
                let db = client.db(this.custOptions.db);
                let cnt = db.collection(collection).find(query).count();
                if (error) {
                    reject(error);
                } else {
                    resolve(cnt);
                }
                client.close();
            });
        });
        return q;
    }

    removeSync(collection: string, query: Object): any {
        let result: any;
        this.remove(collection, query).then((rec: any) => {
            result = rec;
        }, (err) => {
            result = {};
        });
        while (!result) {
            deasync.runLoopOnce();
        }
        return result;
    }
};
